package com.springstudy.shiro.shiro;

import com.springstudy.shiro.constants.Constants;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

/**
 * 自定义的Realm，Realm中定义了获取角色权限和登陆信息的逻辑，用于后续的校验
 * 这里继承了AuthorizingRealm，这个Realm提供了获取角色权限和登陆信息的接口
 * 其他类型的Realm提供的接口可能会有所区别，具体可以参考网上的文档
 *
 * @author chenrongrong
 * @since 2020/3/10 15:49
 */
@Component
public class Realm extends AuthorizingRealm {

    /**
     * 限制token的类型
     * @param token
     * @return
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

    /**
     * 权限验证
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //这里可以获取当前用户信息

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //设置账户角色，实际使用中可通过查询数据库获取相关信息
        Set<String> roles = new HashSet<>();
        if(Constants.ADMIN_ACCOUNT_NAME.equals(principalCollection.getPrimaryPrincipal().toString())) {
            roles.add("admin");
        }
        roles.add("custom");

        authorizationInfo.setRoles(roles);
        //设置账户权限，实际使用中可通过查询数据库获取相关信息
        Set<String> permissions = new HashSet<>();
        permissions.add("test:add");
        permissions.add("test:update");
        permissions.add("test:view");
        permissions.add("test:delete");
        authorizationInfo.setStringPermissions(permissions);

        return authorizationInfo;
    }


    /**
     * 登陆验证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取登陆用户名
        String username = authenticationToken.getPrincipal().toString();
        //也可以获取密码
        //String password = authenticationToken.getCredentials().toString();

        //这里可以根据用户名从数据库查询真正的密码
        String truePassword = "123456";

        //这里传入用户名和真实的密码
        //需要注意，在这个方法中不需要对密码进行比对，很多教程中在这里进行密码比对虽然也可以实现校验，但是无法使用自定义的matcher
        //实际上shiro在这之后会对传入的token和这里返回的AuthenticationInfo的密码使用默认的matcher进行比对，如果比对不同也会提示错误
        return new SimpleAuthenticationInfo(username, truePassword, "realm");
    }
}
